﻿#include "asycipc/backpressure.hpp"

#include <stdexcept>

namespace asycipc {

BackpressureController::BackpressureController(std::size_t high_watermark,
                                               std::size_t low_watermark)
    : high_watermark_(high_watermark), low_watermark_(low_watermark) {
  if (low_watermark_ > high_watermark_) {
    throw std::invalid_argument("low watermark must be <= high watermark");
  }
}

void BackpressureController::SetHandler(std::function<void(bool)> handler) {
  std::lock_guard<std::mutex> lock(mutex_);
  handler_ = std::move(handler);
}

void BackpressureController::Update(std::size_t current_bytes) {
  std::function<void(bool)> handler;
  bool should_notify = false;
  bool new_state = false;
  {
    std::lock_guard<std::mutex> lock(mutex_);
    if (!backpressured_ && current_bytes >= high_watermark_) {
      backpressured_ = true;
      should_notify = true;
      new_state = true;
    } else if (backpressured_ && current_bytes <= low_watermark_) {
      backpressured_ = false;
      should_notify = true;
      new_state = false;
    }
    handler = handler_;
  }
  if (should_notify && handler) {
    handler(new_state);
  }
}

bool BackpressureController::IsBackpressured() const {
  std::lock_guard<std::mutex> lock(mutex_);
  return backpressured_;
}

}  // namespace asycipc
